<!DOCTYPE html>
<html lang="zh-CN" dir="ltr">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>7.3 跨组件状态共享 | 落光的Pro博客</title>
    <meta name="description" content="Vite & Vue powered static site generator.">
    <link rel="preload stylesheet" href="./assets/style.4b0df91d.css" as="style">
    
    <script type="module" src="./assets/app.0acbd3fd.js"></script>
    <link rel="preload" href="./assets/inter-roman-latin.2ed14f66.woff2" as="font" type="font/woff2" crossorigin="">
    <link rel="modulepreload" href="./assets/chunks/framework.eaf25f5b.js">
    <link rel="modulepreload" href="./assets/chunks/theme.ce44a0e6.js">
    <link rel="modulepreload" href="./assets/largeFrontEnd_flutter_chapter7_provider.md.ab590744.lean.js">
    <script id="check-dark-light">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
  </head>
  <body>
    <div id="app"><div class="Layout" data-v-1919c326><!--[--><!--]--><!--[--><span tabindex="-1" data-v-0f60ec36></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-0f60ec36> Skip to content </a><!--]--><!----><header class="VPNav" data-v-1919c326 data-v-7e5bc4a5><div class="VPNavBar has-sidebar" data-v-7e5bc4a5 data-v-a0fd61f4><div class="container" data-v-a0fd61f4><div class="title" data-v-a0fd61f4><div class="VPNavBarTitle has-sidebar" data-v-a0fd61f4 data-v-86d1bed8><a class="title" href="./" data-v-86d1bed8><!--[--><!--]--><!--[--><img class="VPImage logo" src="./icon-radius.png" alt data-v-8426fc1a><!--]--><!--[-->落光的Pro博客<!--]--><!--[--><!--]--></a></div></div><div class="content" data-v-a0fd61f4><div class="curtain" data-v-a0fd61f4></div><div class="content-body" data-v-a0fd61f4><!--[--><!--]--><div class="VPNavBarSearch search" style="--vp-meta-key:&#39;Meta&#39;;" data-v-a0fd61f4><!--[--><!----><div id="local-search"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><svg class="DocSearch-Search-Icon" width="20" height="20" viewBox="0 0 20 20" aria-label="search icon"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-a0fd61f4 data-v-7f418b0f><span id="main-nav-aria-label" class="visually-hidden" data-v-7f418b0f>Main Navigation</span><!--[--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-9c007e85><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-9c007e85><span class="text" data-v-9c007e85><!----><span data-v-9c007e85>大前端</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-9c007e85><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-9c007e85><div class="VPMenu" data-v-9c007e85 data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuLink" data-v-e7ea1737 data-v-43f1e123><a class="VPLink link" href="./largeFrontEnd/webFrontEnd/md/01.html" data-v-43f1e123><!--[-->Web前端<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-e7ea1737 data-v-43f1e123><a class="VPLink link" href="./largeFrontEnd/uniapp/" data-v-43f1e123><!--[-->Uni-app<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-e7ea1737 data-v-43f1e123><a class="VPLink link" href="./largeFrontEnd/weChatMiniProgram/" data-v-43f1e123><!--[-->微信小程序<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-e7ea1737 data-v-43f1e123><a class="VPLink link" href="./largeFrontEnd/electron/" data-v-43f1e123><!--[-->Electron<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-e7ea1737 data-v-43f1e123><a class="VPLink link" href="./largeFrontEnd/flutter/" data-v-43f1e123><!--[-->Flutter<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-e7ea1737 data-v-43f1e123><a class="VPLink link" href="./largeFrontEnd/interview/01.html" data-v-43f1e123><!--[-->前端面试题<!--]--></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="./backEnd/" tabindex="0" data-v-7f418b0f data-v-42ef59de><!--[--><span data-v-42ef59de>后端</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="./linux/" tabindex="0" data-v-7f418b0f data-v-42ef59de><!--[--><span data-v-42ef59de>Linux</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="./myTeam/" tabindex="0" data-v-7f418b0f data-v-42ef59de><!--[--><span data-v-42ef59de>我的团队</span><!--]--></a><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-a0fd61f4 data-v-f6a63727><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-f6a63727 data-v-ce54a7d1 data-v-b1685198><span class="check" data-v-b1685198><span class="icon" data-v-b1685198><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-ce54a7d1><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-ce54a7d1><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-a0fd61f4 data-v-0394ad82 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://gitee.com/luoguangguang" aria-label="github" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink no-icon" href="..." aria-label="cool link" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Dribbble</title><path d="M12...6.38z"/></svg></a><!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-a0fd61f4 data-v-40855f84 data-v-9c007e85><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-9c007e85><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="icon" data-v-9c007e85><circle cx="12" cy="12" r="2"></circle><circle cx="19" cy="12" r="2"></circle><circle cx="5" cy="12" r="2"></circle></svg></button><div class="menu" data-v-9c007e85><div class="VPMenu" data-v-9c007e85 data-v-e7ea1737><!----><!--[--><!--[--><!----><div class="group" data-v-40855f84><div class="item appearance" data-v-40855f84><p class="label" data-v-40855f84>Appearance</p><div class="appearance-action" data-v-40855f84><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-40855f84 data-v-ce54a7d1 data-v-b1685198><span class="check" data-v-b1685198><span class="icon" data-v-b1685198><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-ce54a7d1><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-ce54a7d1><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div></div></div><div class="group" data-v-40855f84><div class="item social-links" data-v-40855f84><div class="VPSocialLinks social-links-list" data-v-40855f84 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://gitee.com/luoguangguang" aria-label="github" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink no-icon" href="..." aria-label="cool link" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Dribbble</title><path d="M12...6.38z"/></svg></a><!--]--></div></div></div><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-a0fd61f4 data-v-e5dd9c1c><span class="container" data-v-e5dd9c1c><span class="top" data-v-e5dd9c1c></span><span class="middle" data-v-e5dd9c1c></span><span class="bottom" data-v-e5dd9c1c></span></span></button></div></div></div></div><!----></header><div class="VPLocalNav reached-top" data-v-1919c326 data-v-79c8c1df><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-79c8c1df><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="menu-icon" data-v-79c8c1df><path d="M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z"></path><path d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z"></path><path d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z"></path><path d="M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z"></path></svg><span class="menu-text" data-v-79c8c1df>Menu</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-79c8c1df data-v-1c15a60a><button data-v-1c15a60a>Return to top</button><!----></div></div><aside class="VPSidebar" data-v-1919c326 data-v-b00e2fdd><div class="curtain" data-v-b00e2fdd></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-b00e2fdd><span class="visually-hidden" id="sidebar-aria-label" data-v-b00e2fdd> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="group" data-v-b00e2fdd><section class="VPSidebarItem level-0 collapsible" data-v-b00e2fdd data-v-e31bd47b><div class="item" role="button" tabindex="0" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><h2 class="text" data-v-e31bd47b>Flutter入门到实战</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-e31bd47b><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-e31bd47b><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-e31bd47b><!--[--><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter1/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第一章 初识Flutter</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter2/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第二章 简介</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter3/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第三章 基础组件</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter4/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第四章 布局类组件</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter5/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第五章 容器类Widget</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter6/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第六章 可滚动组件</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter7/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第七章 功能型Widget简介</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter8/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第八章 事件处理与通知</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter9/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第九章 动画</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter10/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第十章 自定义组件</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter11/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第十一章 文件操作</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter12/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第十二章 Flutter 扩展</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter13/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第十三章 多语言</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter14/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第十四章 高级进阶</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-1919c326 data-v-669faec9><div class="VPDoc has-sidebar has-aside" data-v-669faec9 data-v-6b87e69f><!--[--><!--]--><div class="container" data-v-6b87e69f><div class="aside" data-v-6b87e69f><div class="aside-curtain" data-v-6b87e69f></div><div class="aside-container" data-v-6b87e69f><div class="aside-content" data-v-6b87e69f><div class="VPDocAside" data-v-6b87e69f data-v-3f215769><!--[--><!--]--><!--[--><!--]--><div class="VPDocAsideOutline" role="navigation" data-v-3f215769 data-v-6ae8e080><div class="content" data-v-6ae8e080><div class="outline-marker" data-v-6ae8e080></div><div class="outline-title" role="heading" data-v-6ae8e080>On this page</div><nav aria-labelledby="doc-outline-aria-label" data-v-6ae8e080><span class="visually-hidden" id="doc-outline-aria-label" data-v-6ae8e080> Table of Contents for current page </span><ul class="root" data-v-6ae8e080 data-v-d0ee3533><!--[--><!--]--></ul></nav></div></div><!--[--><!--]--><div class="spacer" data-v-3f215769></div><!--[--><!--]--><div class="VPDocAsideCarbonAds" data-v-3f215769><div class="VPCarbonAds" data-v-2e1efd59></div></div><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-6b87e69f><div class="content-container" data-v-6b87e69f><!--[--><!--]--><!----><main class="main" data-v-6b87e69f><div style="position:relative;" class="vp-doc _largeFrontEnd_flutter_chapter7_provider" data-v-6b87e69f><div><h1 id="_7-3-跨组件状态共享" tabindex="-1">7.3 跨组件状态共享 <a class="header-anchor" href="#_7-3-跨组件状态共享" aria-label="Permalink to &quot;7.3 跨组件状态共享&quot;">​</a></h1><h2 id="_7-3-1-通过事件同步状态" tabindex="-1">7.3.1 通过事件同步状态 <a class="header-anchor" href="#_7-3-1-通过事件同步状态" aria-label="Permalink to &quot;7.3.1 通过事件同步状态&quot;">​</a></h2><p>在 Flutter 开发中，状态管理是一个永恒的话题。一般的原则是：如果状态是组件私有的，则应该由组件自己管理；如果状态要跨组件共享，则该状态应该由各个组件共同的父元素来管理。对于组件私有的状态管理很好理解，但对于跨组件共享的状态，管理的方式就比较多了，如使用全局事件总线EventBus（将在下一章中介绍），它是一个观察者模式的实现，通过它就可以实现跨组件状态同步：状态持有方（发布者）负责更新、发布状态，状态使用方（观察者）监听状态改变事件来执行一些操作。下面我们看一个登录状态同步的简单示例：</p><p>定义事件：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">enum</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Event</span><span style="color:#E1E4E8;">{</span></span>
<span class="line"><span style="color:#E1E4E8;">  login,</span></span>
<span class="line"><span style="color:#E1E4E8;">  ... </span><span style="color:#6A737D;">//省略其他事件</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">enum</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Event</span><span style="color:#24292E;">{</span></span>
<span class="line"><span style="color:#24292E;">  login,</span></span>
<span class="line"><span style="color:#24292E;">  ... </span><span style="color:#6A737D;">//省略其他事件</span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><p>登录页代码大致如下：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// 登录状态改变后发布状态改变事件</span></span>
<span class="line"><span style="color:#E1E4E8;">bus.</span><span style="color:#B392F0;">emit</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">Event</span><span style="color:#E1E4E8;">.login);</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// 登录状态改变后发布状态改变事件</span></span>
<span class="line"><span style="color:#24292E;">bus.</span><span style="color:#6F42C1;">emit</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">Event</span><span style="color:#24292E;">.login);</span></span></code></pre></div><p>依赖登录状态的页面：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">void</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">onLoginChanged</span><span style="color:#E1E4E8;">(e){</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#6A737D;">//登录状态变化处理逻辑</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583;">@override</span></span>
<span class="line"><span style="color:#F97583;">void</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">initState</span><span style="color:#E1E4E8;">() {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#6A737D;">//订阅登录状态改变事件</span></span>
<span class="line"><span style="color:#E1E4E8;">  bus.</span><span style="color:#F97583;">on</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">Event</span><span style="color:#E1E4E8;">.login,onLogin);</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">super</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">initState</span><span style="color:#E1E4E8;">();</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583;">@override</span></span>
<span class="line"><span style="color:#F97583;">void</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">dispose</span><span style="color:#E1E4E8;">() {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#6A737D;">//取消订阅</span></span>
<span class="line"><span style="color:#E1E4E8;">  bus.</span><span style="color:#B392F0;">off</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">Event</span><span style="color:#E1E4E8;">.login,onLogin);</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">super</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">dispose</span><span style="color:#E1E4E8;">();</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">void</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">onLoginChanged</span><span style="color:#24292E;">(e){</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6A737D;">//登录状态变化处理逻辑</span></span>
<span class="line"><span style="color:#24292E;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;">@override</span></span>
<span class="line"><span style="color:#D73A49;">void</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">initState</span><span style="color:#24292E;">() {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6A737D;">//订阅登录状态改变事件</span></span>
<span class="line"><span style="color:#24292E;">  bus.</span><span style="color:#D73A49;">on</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">Event</span><span style="color:#24292E;">.login,onLogin);</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">super</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">initState</span><span style="color:#24292E;">();</span></span>
<span class="line"><span style="color:#24292E;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;">@override</span></span>
<span class="line"><span style="color:#D73A49;">void</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">dispose</span><span style="color:#24292E;">() {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6A737D;">//取消订阅</span></span>
<span class="line"><span style="color:#24292E;">  bus.</span><span style="color:#6F42C1;">off</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">Event</span><span style="color:#24292E;">.login,onLogin);</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">super</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">dispose</span><span style="color:#24292E;">();</span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><p>我们可以发现，通过观察者模式来实现跨组件状态共享有一些明显的缺点：</p><ol><li>必须显式定义各种事件，不好管理。</li><li>订阅者必须需显式注册状态改变回调，也必须在组件销毁时手动去解绑回调以避免内存泄露。</li></ol><p>在Flutter当中有没有更好的跨组件状态管理方式了呢？答案是肯定的，那怎么做的？我们想想前面介绍的<code>InheritedWidget</code>，它的天生特性就是能绑定<code>InheritedWidget</code>与依赖它的子孙组件的依赖关系，并且当<code>InheritedWidget</code>数据发生变化时，可以自动更新依赖的子孙组件！利用这个特性，我们可以将需要跨组件共享的状态保存在<code>InheritedWidget</code>中，然后在子组件中引用<code>InheritedWidget</code>即可，Flutter社区著名的Provider包正是基于这个思想实现的一套跨组件状态共享解决方案，接下来我们便详细介绍一下Provider的用法及原理。</p><h2 id="_7-3-2-provider" tabindex="-1">7.3.2 Provider <a class="header-anchor" href="#_7-3-2-provider" aria-label="Permalink to &quot;7.3.2 Provider&quot;">​</a></h2><p>Provider是Flutter官方出的状态管理包，为了加强读者对其原理的理解，我们不直接去看Provider包的源代码，相反，我会带着你根据上面描述的通过<code>InheritedWidget</code>实现的思路来一步一步地实现一个最小功能的Provider。</p><h3 id="_1-自实现provider" tabindex="-1">1. 自实现Provider <a class="header-anchor" href="#_1-自实现provider" aria-label="Permalink to &quot;1. 自实现Provider&quot;">​</a></h3><p>首先，我们需要一个能够保存共享数据的<code>InheritedWidget</code>，由于具体业务数据类型不可预期，为了通用性，我们使用泛型，定义一个通用的<code>InheritedProvider</code>类，它继承自<code>InheritedWidget</code>：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// 一个通用的InheritedWidget，保存需要跨组件共享的状态</span></span>
<span class="line"><span style="color:#F97583;">class</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">InheritedProvider</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt; </span><span style="color:#F97583;">extends</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">InheritedWidget</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">InheritedProvider</span><span style="color:#E1E4E8;">({</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">required</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">this</span><span style="color:#E1E4E8;">.data,</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">required</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Widget</span><span style="color:#E1E4E8;"> child,</span></span>
<span class="line"><span style="color:#E1E4E8;">  }) </span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">super</span><span style="color:#E1E4E8;">(child</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> child);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">final</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;"> data;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">@override</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">bool</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">updateShouldNotify</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">InheritedProvider</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt; old) {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">//在此简单返回true，则每次更新都会调用依赖其的子孙节点的`didChangeDependencies`。</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">true</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// 一个通用的InheritedWidget，保存需要跨组件共享的状态</span></span>
<span class="line"><span style="color:#D73A49;">class</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">InheritedProvider</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt; </span><span style="color:#D73A49;">extends</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">InheritedWidget</span><span style="color:#24292E;"> {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">InheritedProvider</span><span style="color:#24292E;">({</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">required</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">this</span><span style="color:#24292E;">.data,</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">required</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Widget</span><span style="color:#24292E;"> child,</span></span>
<span class="line"><span style="color:#24292E;">  }) </span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">super</span><span style="color:#24292E;">(child</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> child);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">final</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">T</span><span style="color:#24292E;"> data;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">@override</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">bool</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">updateShouldNotify</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">InheritedProvider</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt; old) {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6A737D;">//在此简单返回true，则每次更新都会调用依赖其的子孙节点的`didChangeDependencies`。</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">true</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><p>数据保存的地方有了，那么接下来我们需要做的就是在数据发生变化的时候来重新构建<code>InheritedProvider</code>，那么现在就面临两个问题：</p><ol><li>数据发生变化怎么通知？</li><li>谁来重新构建<code>InheritedProvider</code>？</li></ol><p>第一个问题其实很好解决，我们当然可以使用之前介绍的eventBus来进行事件通知，但是为了更贴近Flutter开发，我们使用Flutter SDK中提供的<code>ChangeNotifier</code>类 ，它继承自<code>Listenable</code>，也实现了一个Flutter风格的发布者-订阅者模式，<code>ChangeNotifier</code>定义大致如下：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">class</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">ChangeNotifier</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">implements</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Listenable</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">List</span><span style="color:#E1E4E8;"> listeners</span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;">[];</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">@override</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">void</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">addListener</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">VoidCallback</span><span style="color:#E1E4E8;"> listener) {</span></span>
<span class="line"><span style="color:#E1E4E8;">     </span><span style="color:#6A737D;">//添加监听器</span></span>
<span class="line"><span style="color:#E1E4E8;">     listeners.</span><span style="color:#B392F0;">add</span><span style="color:#E1E4E8;">(listener);</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">@override</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">void</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">removeListener</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">VoidCallback</span><span style="color:#E1E4E8;"> listener) {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">//移除监听器</span></span>
<span class="line"><span style="color:#E1E4E8;">    listeners.</span><span style="color:#B392F0;">remove</span><span style="color:#E1E4E8;">(listener);</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">void</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">notifyListeners</span><span style="color:#E1E4E8;">() {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">//通知所有监听器，触发监听器回调 </span></span>
<span class="line"><span style="color:#E1E4E8;">    listeners.</span><span style="color:#B392F0;">forEach</span><span style="color:#E1E4E8;">((item)</span><span style="color:#F97583;">=&gt;</span><span style="color:#B392F0;">item</span><span style="color:#E1E4E8;">());</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span></span>
<span class="line"><span style="color:#E1E4E8;">  ... </span><span style="color:#6A737D;">//省略无关代码</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">class</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">ChangeNotifier</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">implements</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Listenable</span><span style="color:#24292E;"> {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">List</span><span style="color:#24292E;"> listeners</span><span style="color:#D73A49;">=</span><span style="color:#24292E;">[];</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">@override</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">void</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">addListener</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">VoidCallback</span><span style="color:#24292E;"> listener) {</span></span>
<span class="line"><span style="color:#24292E;">     </span><span style="color:#6A737D;">//添加监听器</span></span>
<span class="line"><span style="color:#24292E;">     listeners.</span><span style="color:#6F42C1;">add</span><span style="color:#24292E;">(listener);</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">@override</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">void</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">removeListener</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">VoidCallback</span><span style="color:#24292E;"> listener) {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6A737D;">//移除监听器</span></span>
<span class="line"><span style="color:#24292E;">    listeners.</span><span style="color:#6F42C1;">remove</span><span style="color:#24292E;">(listener);</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"><span style="color:#24292E;">  </span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">void</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">notifyListeners</span><span style="color:#24292E;">() {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6A737D;">//通知所有监听器，触发监听器回调 </span></span>
<span class="line"><span style="color:#24292E;">    listeners.</span><span style="color:#6F42C1;">forEach</span><span style="color:#24292E;">((item)</span><span style="color:#D73A49;">=&gt;</span><span style="color:#6F42C1;">item</span><span style="color:#24292E;">());</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"><span style="color:#24292E;">   </span></span>
<span class="line"><span style="color:#24292E;">  ... </span><span style="color:#6A737D;">//省略无关代码</span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><p>我们可以通过调用<code>addListener()</code>和<code>removeListener()</code>来添加、移除监听器（订阅者）；通过调用<code>notifyListeners()</code> 可以触发所有监听器回调。</p><p>现在，我们将要共享的状态放到一个Model类中，然后让它继承自<code>ChangeNotifier</code>，这样当共享的状态改变时，我们只需要调用<code>notifyListeners()</code> 来通知订阅者，然后由订阅者来重新构建<code>InheritedProvider</code>，这也是第二个问题的答案！接下来我们便实现这个订阅者类：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">class</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">ChangeNotifierProvider</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">extends</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">ChangeNotifier</span><span style="color:#E1E4E8;">&gt; </span><span style="color:#F97583;">extends</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">StatefulWidget</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">ChangeNotifierProvider</span><span style="color:#E1E4E8;">({</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#79B8FF;">Key</span><span style="color:#F97583;">?</span><span style="color:#E1E4E8;"> key,</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#79B8FF;">this</span><span style="color:#E1E4E8;">.data,</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#79B8FF;">this</span><span style="color:#E1E4E8;">.child,</span></span>
<span class="line"><span style="color:#E1E4E8;">  });</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">final</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Widget</span><span style="color:#E1E4E8;"> child;</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">final</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;"> data;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#6A737D;">//定义一个便捷方法，方便子树中的widget获取共享数据</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">static</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">of</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt;(</span><span style="color:#79B8FF;">BuildContext</span><span style="color:#E1E4E8;"> context) {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">final</span><span style="color:#E1E4E8;"> type </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">_typeOf</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">InheritedProvider</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt;&gt;();</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">final</span><span style="color:#E1E4E8;"> provider </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;">  context.</span><span style="color:#B392F0;">dependOnInheritedWidgetOfExactType</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">InheritedProvider</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt;&gt;();</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> provider.data;</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">@override</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">_ChangeNotifierProviderState</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt; </span><span style="color:#B392F0;">createState</span><span style="color:#E1E4E8;">() </span><span style="color:#F97583;">=&gt;</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">_ChangeNotifierProviderState</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt;();</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">class</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">ChangeNotifierProvider</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">extends</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">ChangeNotifier</span><span style="color:#24292E;">&gt; </span><span style="color:#D73A49;">extends</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">StatefulWidget</span><span style="color:#24292E;"> {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">ChangeNotifierProvider</span><span style="color:#24292E;">({</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#005CC5;">Key</span><span style="color:#D73A49;">?</span><span style="color:#24292E;"> key,</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#005CC5;">this</span><span style="color:#24292E;">.data,</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#005CC5;">this</span><span style="color:#24292E;">.child,</span></span>
<span class="line"><span style="color:#24292E;">  });</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">final</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Widget</span><span style="color:#24292E;"> child;</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">final</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">T</span><span style="color:#24292E;"> data;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6A737D;">//定义一个便捷方法，方便子树中的widget获取共享数据</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">static</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">T</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">of</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt;(</span><span style="color:#005CC5;">BuildContext</span><span style="color:#24292E;"> context) {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">final</span><span style="color:#24292E;"> type </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">_typeOf</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">InheritedProvider</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt;&gt;();</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">final</span><span style="color:#24292E;"> provider </span><span style="color:#D73A49;">=</span><span style="color:#24292E;">  context.</span><span style="color:#6F42C1;">dependOnInheritedWidgetOfExactType</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">InheritedProvider</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt;&gt;();</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> provider.data;</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">@override</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">_ChangeNotifierProviderState</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt; </span><span style="color:#6F42C1;">createState</span><span style="color:#24292E;">() </span><span style="color:#D73A49;">=&gt;</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">_ChangeNotifierProviderState</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt;();</span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><p>该类继承<code>StatefulWidget</code>，然后定义了一个<code>of()</code>静态方法供子类方便获取Widget树中的<code>InheritedProvider</code>中保存的共享状态(model)，下面我们实现该类对应的<code>_ChangeNotifierProviderState</code>类：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">class</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">_ChangeNotifierProviderState</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">extends</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">ChangeNotifier</span><span style="color:#E1E4E8;">&gt; </span><span style="color:#F97583;">extends</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">State</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">ChangeNotifierProvider</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt;&gt; {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">void</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">update</span><span style="color:#E1E4E8;">() {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">//如果数据发生变化（model类调用了notifyListeners），重新构建InheritedProvider</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">setState</span><span style="color:#E1E4E8;">(() </span><span style="color:#F97583;">=&gt;</span><span style="color:#E1E4E8;"> {});</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">@override</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">void</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">didUpdateWidget</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">ChangeNotifierProvider</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt; oldWidget) {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">//当Provider更新时，如果新旧数据不&quot;==&quot;，则解绑旧数据监听，同时添加新数据监听</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">if</span><span style="color:#E1E4E8;"> (widget.data </span><span style="color:#F97583;">!=</span><span style="color:#E1E4E8;"> oldWidget.data) {</span></span>
<span class="line"><span style="color:#E1E4E8;">      oldWidget.data.</span><span style="color:#B392F0;">removeListener</span><span style="color:#E1E4E8;">(update);</span></span>
<span class="line"><span style="color:#E1E4E8;">      widget.data.</span><span style="color:#B392F0;">addListener</span><span style="color:#E1E4E8;">(update);</span></span>
<span class="line"><span style="color:#E1E4E8;">    }</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#79B8FF;">super</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">didUpdateWidget</span><span style="color:#E1E4E8;">(oldWidget);</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">@override</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">void</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">initState</span><span style="color:#E1E4E8;">() {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">// 给model添加监听器</span></span>
<span class="line"><span style="color:#E1E4E8;">    widget.data.</span><span style="color:#B392F0;">addListener</span><span style="color:#E1E4E8;">(update);</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#79B8FF;">super</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">initState</span><span style="color:#E1E4E8;">();</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">@override</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">void</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">dispose</span><span style="color:#E1E4E8;">() {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">// 移除model的监听器</span></span>
<span class="line"><span style="color:#E1E4E8;">    widget.data.</span><span style="color:#B392F0;">removeListener</span><span style="color:#E1E4E8;">(update);</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#79B8FF;">super</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">dispose</span><span style="color:#E1E4E8;">();</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">@override</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">Widget</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">build</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">BuildContext</span><span style="color:#E1E4E8;"> context) {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">InheritedProvider</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt;(</span></span>
<span class="line"><span style="color:#E1E4E8;">      data</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> widget.data,</span></span>
<span class="line"><span style="color:#E1E4E8;">      child</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> widget.child,</span></span>
<span class="line"><span style="color:#E1E4E8;">    );</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">class</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">_ChangeNotifierProviderState</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">extends</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">ChangeNotifier</span><span style="color:#24292E;">&gt; </span><span style="color:#D73A49;">extends</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">State</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">ChangeNotifierProvider</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt;&gt; {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">void</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">update</span><span style="color:#24292E;">() {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6A737D;">//如果数据发生变化（model类调用了notifyListeners），重新构建InheritedProvider</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6F42C1;">setState</span><span style="color:#24292E;">(() </span><span style="color:#D73A49;">=&gt;</span><span style="color:#24292E;"> {});</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">@override</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">void</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">didUpdateWidget</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">ChangeNotifierProvider</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt; oldWidget) {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6A737D;">//当Provider更新时，如果新旧数据不&quot;==&quot;，则解绑旧数据监听，同时添加新数据监听</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">if</span><span style="color:#24292E;"> (widget.data </span><span style="color:#D73A49;">!=</span><span style="color:#24292E;"> oldWidget.data) {</span></span>
<span class="line"><span style="color:#24292E;">      oldWidget.data.</span><span style="color:#6F42C1;">removeListener</span><span style="color:#24292E;">(update);</span></span>
<span class="line"><span style="color:#24292E;">      widget.data.</span><span style="color:#6F42C1;">addListener</span><span style="color:#24292E;">(update);</span></span>
<span class="line"><span style="color:#24292E;">    }</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#005CC5;">super</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">didUpdateWidget</span><span style="color:#24292E;">(oldWidget);</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">@override</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">void</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">initState</span><span style="color:#24292E;">() {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6A737D;">// 给model添加监听器</span></span>
<span class="line"><span style="color:#24292E;">    widget.data.</span><span style="color:#6F42C1;">addListener</span><span style="color:#24292E;">(update);</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#005CC5;">super</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">initState</span><span style="color:#24292E;">();</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">@override</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">void</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">dispose</span><span style="color:#24292E;">() {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6A737D;">// 移除model的监听器</span></span>
<span class="line"><span style="color:#24292E;">    widget.data.</span><span style="color:#6F42C1;">removeListener</span><span style="color:#24292E;">(update);</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#005CC5;">super</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">dispose</span><span style="color:#24292E;">();</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">@override</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">Widget</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">build</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">BuildContext</span><span style="color:#24292E;"> context) {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">InheritedProvider</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt;(</span></span>
<span class="line"><span style="color:#24292E;">      data</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> widget.data,</span></span>
<span class="line"><span style="color:#24292E;">      child</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> widget.child,</span></span>
<span class="line"><span style="color:#24292E;">    );</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><p>可以看到<code>_ChangeNotifierProviderState</code>类的主要作用就是监听到共享状态（model）改变时重新构建Widget树。注意，在<code>_ChangeNotifierProviderState</code>类中调用<code>setState()</code>方法，<code>widget.child</code>始终是同一个，所以执行build时，<code>InheritedProvider</code>的child引用的始终是同一个子widget，所以<code>widget.child</code>并不会重新<code>build</code>，这也就相当于对<code>child</code>进行了缓存！当然如果<code>ChangeNotifierProvider</code>父级Widget重新build时，则其传入的<code>child</code>便有可能会发生变化。</p><p>现在我们所需要的各个工具类都已完成，下面我们通过一个购物车的例子来看看怎么使用上面的这些类。</p><h3 id="_2-购物车示例" tabindex="-1">2. 购物车示例 <a class="header-anchor" href="#_2-购物车示例" aria-label="Permalink to &quot;2. 购物车示例&quot;">​</a></h3><p>我们需要实现一个显示购物车中所有商品总价的功能：</p><ol><li>向购物车中添加新商品时总价更新</li></ol><p>定义一个<code>Item</code>类，用于表示商品信息：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">class</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Item</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">Item</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">this</span><span style="color:#E1E4E8;">.price, </span><span style="color:#79B8FF;">this</span><span style="color:#E1E4E8;">.count);</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">double</span><span style="color:#E1E4E8;"> price; </span><span style="color:#6A737D;">//商品单价</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">int</span><span style="color:#E1E4E8;"> count; </span><span style="color:#6A737D;">// 商品份数</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#6A737D;">//... 省略其他属性</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">class</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Item</span><span style="color:#24292E;"> {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">Item</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">this</span><span style="color:#24292E;">.price, </span><span style="color:#005CC5;">this</span><span style="color:#24292E;">.count);</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">double</span><span style="color:#24292E;"> price; </span><span style="color:#6A737D;">//商品单价</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">int</span><span style="color:#24292E;"> count; </span><span style="color:#6A737D;">// 商品份数</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6A737D;">//... 省略其他属性</span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><p>定义一个保存购物车内商品数据的<code>CartModel</code>类:</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">class</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">CartModel</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">extends</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">ChangeNotifier</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#6A737D;">// 用于保存购物车中商品列表</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">final</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">List</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">Item</span><span style="color:#E1E4E8;">&gt; _items </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> [];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#6A737D;">// 禁止改变购物车里的商品信息</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">UnmodifiableListView</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">Item</span><span style="color:#E1E4E8;">&gt; </span><span style="color:#F97583;">get</span><span style="color:#E1E4E8;"> items </span><span style="color:#F97583;">=&gt;</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">UnmodifiableListView</span><span style="color:#E1E4E8;">(_items);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#6A737D;">// 购物车中商品的总价</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">double</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">get</span><span style="color:#E1E4E8;"> totalPrice </span><span style="color:#F97583;">=&gt;</span></span>
<span class="line"><span style="color:#E1E4E8;">      _items.</span><span style="color:#B392F0;">fold</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">0</span><span style="color:#E1E4E8;">, (value, item) </span><span style="color:#F97583;">=&gt;</span><span style="color:#E1E4E8;"> value </span><span style="color:#F97583;">+</span><span style="color:#E1E4E8;"> item.count </span><span style="color:#F97583;">*</span><span style="color:#E1E4E8;"> item.price);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#6A737D;">// 将 [item] 添加到购物车。这是唯一一种能从外部改变购物车的方法。</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">void</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">add</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">Item</span><span style="color:#E1E4E8;"> item) {</span></span>
<span class="line"><span style="color:#E1E4E8;">    _items.</span><span style="color:#B392F0;">add</span><span style="color:#E1E4E8;">(item);</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">// 通知监听器（订阅者），重新构建InheritedProvider， 更新状态。</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">notifyListeners</span><span style="color:#E1E4E8;">();</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">class</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">CartModel</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">extends</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">ChangeNotifier</span><span style="color:#24292E;"> {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6A737D;">// 用于保存购物车中商品列表</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">final</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">List</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">Item</span><span style="color:#24292E;">&gt; _items </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> [];</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6A737D;">// 禁止改变购物车里的商品信息</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">UnmodifiableListView</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">Item</span><span style="color:#24292E;">&gt; </span><span style="color:#D73A49;">get</span><span style="color:#24292E;"> items </span><span style="color:#D73A49;">=&gt;</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">UnmodifiableListView</span><span style="color:#24292E;">(_items);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6A737D;">// 购物车中商品的总价</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">double</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">get</span><span style="color:#24292E;"> totalPrice </span><span style="color:#D73A49;">=&gt;</span></span>
<span class="line"><span style="color:#24292E;">      _items.</span><span style="color:#6F42C1;">fold</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">0</span><span style="color:#24292E;">, (value, item) </span><span style="color:#D73A49;">=&gt;</span><span style="color:#24292E;"> value </span><span style="color:#D73A49;">+</span><span style="color:#24292E;"> item.count </span><span style="color:#D73A49;">*</span><span style="color:#24292E;"> item.price);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6A737D;">// 将 [item] 添加到购物车。这是唯一一种能从外部改变购物车的方法。</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">void</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">add</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">Item</span><span style="color:#24292E;"> item) {</span></span>
<span class="line"><span style="color:#24292E;">    _items.</span><span style="color:#6F42C1;">add</span><span style="color:#24292E;">(item);</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6A737D;">// 通知监听器（订阅者），重新构建InheritedProvider， 更新状态。</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6F42C1;">notifyListeners</span><span style="color:#24292E;">();</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><p><code>CartModel </code>即要跨组件共享的model类。最后我们构建示例页面：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">class</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">ProviderRoute</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">extends</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">StatefulWidget</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">@override</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">_ProviderRouteState</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">createState</span><span style="color:#E1E4E8;">() </span><span style="color:#F97583;">=&gt;</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">_ProviderRouteState</span><span style="color:#E1E4E8;">();</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583;">class</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">_ProviderRouteState</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">extends</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">State</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">ProviderRoute</span><span style="color:#E1E4E8;">&gt; {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">@override</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">Widget</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">build</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">BuildContext</span><span style="color:#E1E4E8;"> context) {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Center</span><span style="color:#E1E4E8;">(</span></span>
<span class="line"><span style="color:#E1E4E8;">      child</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">ChangeNotifierProvider</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">CartModel</span><span style="color:#E1E4E8;">&gt;(</span></span>
<span class="line"><span style="color:#E1E4E8;">        data</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">CartModel</span><span style="color:#E1E4E8;">(),</span></span>
<span class="line"><span style="color:#E1E4E8;">        child</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Builder</span><span style="color:#E1E4E8;">(builder</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> (context) {</span></span>
<span class="line"><span style="color:#E1E4E8;">          </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Column</span><span style="color:#E1E4E8;">(</span></span>
<span class="line"><span style="color:#E1E4E8;">            children</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">&lt;</span><span style="color:#79B8FF;">Widget</span><span style="color:#F97583;">&gt;</span><span style="color:#E1E4E8;">[</span></span>
<span class="line"><span style="color:#E1E4E8;">              </span><span style="color:#79B8FF;">Builder</span><span style="color:#E1E4E8;">(builder</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> (context){</span></span>
<span class="line"><span style="color:#E1E4E8;">                </span><span style="color:#F97583;">var</span><span style="color:#E1E4E8;"> cart</span><span style="color:#F97583;">=</span><span style="color:#79B8FF;">ChangeNotifierProvider</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">of</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">CartModel</span><span style="color:#E1E4E8;">&gt;(context);</span></span>
<span class="line"><span style="color:#E1E4E8;">                </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Text</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;总价: ${</span><span style="color:#79B8FF;">cart</span><span style="color:#9ECBFF;">.</span><span style="color:#79B8FF;">totalPrice</span><span style="color:#9ECBFF;">}&quot;</span><span style="color:#E1E4E8;">);</span></span>
<span class="line"><span style="color:#E1E4E8;">              }),</span></span>
<span class="line"><span style="color:#E1E4E8;">              </span><span style="color:#79B8FF;">Builder</span><span style="color:#E1E4E8;">(builder</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> (context){</span></span>
<span class="line"><span style="color:#E1E4E8;">                </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;ElevatedButton build&quot;</span><span style="color:#E1E4E8;">); </span><span style="color:#6A737D;">//在后面优化部分会用到</span></span>
<span class="line"><span style="color:#E1E4E8;">                </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">ElevatedButton</span><span style="color:#E1E4E8;">(</span></span>
<span class="line"><span style="color:#E1E4E8;">                  child</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Text</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;添加商品&quot;</span><span style="color:#E1E4E8;">),</span></span>
<span class="line"><span style="color:#E1E4E8;">                  onPressed</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> () {</span></span>
<span class="line"><span style="color:#E1E4E8;">                    </span><span style="color:#6A737D;">//给购物车中添加商品，添加后总价会更新</span></span>
<span class="line"><span style="color:#E1E4E8;">                    </span><span style="color:#79B8FF;">ChangeNotifierProvider</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">of</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">CartModel</span><span style="color:#E1E4E8;">&gt;(context).</span><span style="color:#B392F0;">add</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">Item</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">20.0</span><span style="color:#E1E4E8;">, </span><span style="color:#79B8FF;">1</span><span style="color:#E1E4E8;">));</span></span>
<span class="line"><span style="color:#E1E4E8;">                  },</span></span>
<span class="line"><span style="color:#E1E4E8;">                );</span></span>
<span class="line"><span style="color:#E1E4E8;">              }),</span></span>
<span class="line"><span style="color:#E1E4E8;">            ],</span></span>
<span class="line"><span style="color:#E1E4E8;">          );</span></span>
<span class="line"><span style="color:#E1E4E8;">        }),</span></span>
<span class="line"><span style="color:#E1E4E8;">      ),</span></span>
<span class="line"><span style="color:#E1E4E8;">    );</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">class</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">ProviderRoute</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">extends</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">StatefulWidget</span><span style="color:#24292E;"> {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">@override</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">_ProviderRouteState</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">createState</span><span style="color:#24292E;">() </span><span style="color:#D73A49;">=&gt;</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">_ProviderRouteState</span><span style="color:#24292E;">();</span></span>
<span class="line"><span style="color:#24292E;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;">class</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">_ProviderRouteState</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">extends</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">State</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">ProviderRoute</span><span style="color:#24292E;">&gt; {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">@override</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">Widget</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">build</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">BuildContext</span><span style="color:#24292E;"> context) {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Center</span><span style="color:#24292E;">(</span></span>
<span class="line"><span style="color:#24292E;">      child</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">ChangeNotifierProvider</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">CartModel</span><span style="color:#24292E;">&gt;(</span></span>
<span class="line"><span style="color:#24292E;">        data</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">CartModel</span><span style="color:#24292E;">(),</span></span>
<span class="line"><span style="color:#24292E;">        child</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Builder</span><span style="color:#24292E;">(builder</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> (context) {</span></span>
<span class="line"><span style="color:#24292E;">          </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Column</span><span style="color:#24292E;">(</span></span>
<span class="line"><span style="color:#24292E;">            children</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">&lt;</span><span style="color:#005CC5;">Widget</span><span style="color:#D73A49;">&gt;</span><span style="color:#24292E;">[</span></span>
<span class="line"><span style="color:#24292E;">              </span><span style="color:#005CC5;">Builder</span><span style="color:#24292E;">(builder</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> (context){</span></span>
<span class="line"><span style="color:#24292E;">                </span><span style="color:#D73A49;">var</span><span style="color:#24292E;"> cart</span><span style="color:#D73A49;">=</span><span style="color:#005CC5;">ChangeNotifierProvider</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">of</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">CartModel</span><span style="color:#24292E;">&gt;(context);</span></span>
<span class="line"><span style="color:#24292E;">                </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Text</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;总价: ${</span><span style="color:#005CC5;">cart</span><span style="color:#032F62;">.</span><span style="color:#005CC5;">totalPrice</span><span style="color:#032F62;">}&quot;</span><span style="color:#24292E;">);</span></span>
<span class="line"><span style="color:#24292E;">              }),</span></span>
<span class="line"><span style="color:#24292E;">              </span><span style="color:#005CC5;">Builder</span><span style="color:#24292E;">(builder</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> (context){</span></span>
<span class="line"><span style="color:#24292E;">                </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;ElevatedButton build&quot;</span><span style="color:#24292E;">); </span><span style="color:#6A737D;">//在后面优化部分会用到</span></span>
<span class="line"><span style="color:#24292E;">                </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">ElevatedButton</span><span style="color:#24292E;">(</span></span>
<span class="line"><span style="color:#24292E;">                  child</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Text</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;添加商品&quot;</span><span style="color:#24292E;">),</span></span>
<span class="line"><span style="color:#24292E;">                  onPressed</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> () {</span></span>
<span class="line"><span style="color:#24292E;">                    </span><span style="color:#6A737D;">//给购物车中添加商品，添加后总价会更新</span></span>
<span class="line"><span style="color:#24292E;">                    </span><span style="color:#005CC5;">ChangeNotifierProvider</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">of</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">CartModel</span><span style="color:#24292E;">&gt;(context).</span><span style="color:#6F42C1;">add</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">Item</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">20.0</span><span style="color:#24292E;">, </span><span style="color:#005CC5;">1</span><span style="color:#24292E;">));</span></span>
<span class="line"><span style="color:#24292E;">                  },</span></span>
<span class="line"><span style="color:#24292E;">                );</span></span>
<span class="line"><span style="color:#24292E;">              }),</span></span>
<span class="line"><span style="color:#24292E;">            ],</span></span>
<span class="line"><span style="color:#24292E;">          );</span></span>
<span class="line"><span style="color:#24292E;">        }),</span></span>
<span class="line"><span style="color:#24292E;">      ),</span></span>
<span class="line"><span style="color:#24292E;">    );</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><p>运行示例后效果如图7-2所示：</p><p><img src="/assets/7-2.b423b44d.png" alt="provider"></p><p>每次点击”添加商品“按钮，总价就会增加20，我们期望的功能实现了！可能有些读者会疑惑，我们饶了一大圈实现这么简单的功能有意义么？其实，就这个例子来看，只是更新同一个路由页中的一个状态，我们使用<code>ChangeNotifierProvider</code>的优势并不明显，但是如果我们是做一个购物APP呢？由于购物车数据是通常是会在整个APP中共享的，比如会跨路由共享。如果我们将<code>ChangeNotifierProvider</code>放在整个应用的Widget树的根上，那么整个APP就可以共享购物车的数据了，这时<code>ChangeNotifierProvider</code>的优势将会非常明显。</p><p>虽然上面的例子比较简单，但它却将Provider的原理和流程体现的很清楚，图7-3是Provider的原理图：</p><p><img src="/assets/7-3.ffc55f27.png" alt="图7-3"></p><p>Model变化后会自动通知<code>ChangeNotifierProvider</code>（订阅者），<code>ChangeNotifierProvider</code>内部会重新构建<code>InheritedWidget</code>，而依赖该<code>InheritedWidget</code>的子孙Widget就会更新。</p><p>我们可以发现使用Provider，将会带来如下收益：</p><ol><li>我们的业务代码更关注数据了，只要更新Model，则UI会自动更新，而不用在状态改变后再去手动调用<code>setState()</code>来显式更新页面。</li><li>数据改变的消息传递被屏蔽了，我们无需手动去处理状态改变事件的发布和订阅了，这一切都被封装在Provider中了。这真的很棒，帮我们省掉了大量的工作！</li><li>在大型复杂应用中，尤其是需要全局共享的状态非常多时，使用Provider将会大大简化我们的代码逻辑，降低出错的概率，提高开发效率。</li></ol><h2 id="_7-3-3-优化" tabindex="-1">7.3.3 优化 <a class="header-anchor" href="#_7-3-3-优化" aria-label="Permalink to &quot;7.3.3 优化&quot;">​</a></h2><p>我们上面实现的<code>ChangeNotifierProvider</code>是有两个明显缺点：代码组织问题和性能问题，下面我们一一讨论。</p><h3 id="_1-代码组织问题" tabindex="-1">1. 代码组织问题 <a class="header-anchor" href="#_1-代码组织问题" aria-label="Permalink to &quot;1. 代码组织问题&quot;">​</a></h3><p>我们先看一下构建显示总价Text的代码：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#79B8FF;">Builder</span><span style="color:#E1E4E8;">(builder</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> (context){</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">var</span><span style="color:#E1E4E8;"> cart</span><span style="color:#F97583;">=</span><span style="color:#79B8FF;">ChangeNotifierProvider</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">of</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">CartModel</span><span style="color:#E1E4E8;">&gt;(context);</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Text</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;总价: ${</span><span style="color:#79B8FF;">cart</span><span style="color:#9ECBFF;">.</span><span style="color:#79B8FF;">totalPrice</span><span style="color:#9ECBFF;">}&quot;</span><span style="color:#E1E4E8;">);</span></span>
<span class="line"><span style="color:#E1E4E8;">})</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">Builder</span><span style="color:#24292E;">(builder</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> (context){</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">var</span><span style="color:#24292E;"> cart</span><span style="color:#D73A49;">=</span><span style="color:#005CC5;">ChangeNotifierProvider</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">of</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">CartModel</span><span style="color:#24292E;">&gt;(context);</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Text</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;总价: ${</span><span style="color:#005CC5;">cart</span><span style="color:#032F62;">.</span><span style="color:#005CC5;">totalPrice</span><span style="color:#032F62;">}&quot;</span><span style="color:#24292E;">);</span></span>
<span class="line"><span style="color:#24292E;">})</span></span></code></pre></div><p>这段代码有两点可以优化：</p><ol><li>需要显式调用<code>ChangeNotifierProvider.of</code>，当APP内部依赖<code>CartModel</code>很多时，这样的代码将很冗余。</li><li>语义不明确；由于<code>ChangeNotifierProvider</code>是订阅者，那么依赖<code>CartModel</code>的Widget自然就是订阅者，其实也就是状态的消费者，如果我们用<code>Builder</code> 来构建，语义就不是很明确；如果我们能使用一个具有明确语义的Widget，比如就叫<code>Consumer</code>，这样最终的代码语义将会很明确，只要看到<code>Consumer</code>，我们就知道它是依赖某个跨组件或全局的状态。</li></ol><p>为了优化这两个问题，我们可以封装一个<code>Consumer</code> Widget，实现如下：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// 这是一个便捷类，会获得当前context和指定数据类型的Provider</span></span>
<span class="line"><span style="color:#F97583;">class</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Consumer</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt; </span><span style="color:#F97583;">extends</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">StatelessWidget</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">Consumer</span><span style="color:#E1E4E8;">({</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#79B8FF;">Key</span><span style="color:#F97583;">?</span><span style="color:#E1E4E8;"> key,</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">required</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">this</span><span style="color:#E1E4E8;">.builder,</span></span>
<span class="line"><span style="color:#E1E4E8;">  }) </span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">super</span><span style="color:#E1E4E8;">(key</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> key);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">final</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Widget</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Function</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">BuildContext</span><span style="color:#E1E4E8;"> context, </span><span style="color:#79B8FF;">T</span><span style="color:#F97583;">?</span><span style="color:#E1E4E8;"> value) builder;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">@override</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">Widget</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">build</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">BuildContext</span><span style="color:#E1E4E8;"> context) {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">builder</span><span style="color:#E1E4E8;">(</span></span>
<span class="line"><span style="color:#E1E4E8;">      context,</span></span>
<span class="line"><span style="color:#E1E4E8;">      </span><span style="color:#79B8FF;">ChangeNotifierProvider</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">of</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt;(context),</span></span>
<span class="line"><span style="color:#E1E4E8;">    );</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// 这是一个便捷类，会获得当前context和指定数据类型的Provider</span></span>
<span class="line"><span style="color:#D73A49;">class</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Consumer</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt; </span><span style="color:#D73A49;">extends</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">StatelessWidget</span><span style="color:#24292E;"> {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">Consumer</span><span style="color:#24292E;">({</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#005CC5;">Key</span><span style="color:#D73A49;">?</span><span style="color:#24292E;"> key,</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">required</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">this</span><span style="color:#24292E;">.builder,</span></span>
<span class="line"><span style="color:#24292E;">  }) </span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">super</span><span style="color:#24292E;">(key</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> key);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">final</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Widget</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Function</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">BuildContext</span><span style="color:#24292E;"> context, </span><span style="color:#005CC5;">T</span><span style="color:#D73A49;">?</span><span style="color:#24292E;"> value) builder;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">@override</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">Widget</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">build</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">BuildContext</span><span style="color:#24292E;"> context) {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">builder</span><span style="color:#24292E;">(</span></span>
<span class="line"><span style="color:#24292E;">      context,</span></span>
<span class="line"><span style="color:#24292E;">      </span><span style="color:#005CC5;">ChangeNotifierProvider</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">of</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt;(context),</span></span>
<span class="line"><span style="color:#24292E;">    );</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><p><code>Consumer</code>实现非常简单，它通过指定模板参数，然后再内部自动调用<code>ChangeNotifierProvider.of</code>获取相应的Model，并且<code>Consumer</code>这个名字本身也是具有确切语义（消费者）。现在上面的代码块可以优化为如下这样：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#79B8FF;">Consumer</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">CartModel</span><span style="color:#E1E4E8;">&gt;(</span></span>
<span class="line"><span style="color:#E1E4E8;">  builder</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> (context, cart)</span><span style="color:#F97583;">=&gt;</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Text</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;总价: ${</span><span style="color:#79B8FF;">cart</span><span style="color:#9ECBFF;">.</span><span style="color:#79B8FF;">totalPrice</span><span style="color:#9ECBFF;">}&quot;</span><span style="color:#E1E4E8;">);</span></span>
<span class="line"><span style="color:#E1E4E8;">)</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">Consumer</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">CartModel</span><span style="color:#24292E;">&gt;(</span></span>
<span class="line"><span style="color:#24292E;">  builder</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> (context, cart)</span><span style="color:#D73A49;">=&gt;</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Text</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;总价: ${</span><span style="color:#005CC5;">cart</span><span style="color:#032F62;">.</span><span style="color:#005CC5;">totalPrice</span><span style="color:#032F62;">}&quot;</span><span style="color:#24292E;">);</span></span>
<span class="line"><span style="color:#24292E;">)</span></span></code></pre></div><p>是不是很优雅！</p><h3 id="_2-性能问题" tabindex="-1">2. 性能问题 <a class="header-anchor" href="#_2-性能问题" aria-label="Permalink to &quot;2. 性能问题&quot;">​</a></h3><p>上面的代码还有一个性能问题，就在构建”添加按钮“的代码处：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#79B8FF;">Builder</span><span style="color:#E1E4E8;">(builder</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> (context) {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;ElevatedButton build&quot;</span><span style="color:#E1E4E8;">); </span><span style="color:#6A737D;">// 构建时输出日志</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">ElevatedButton</span><span style="color:#E1E4E8;">(</span></span>
<span class="line"><span style="color:#E1E4E8;">    child</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Text</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;添加商品&quot;</span><span style="color:#E1E4E8;">),</span></span>
<span class="line"><span style="color:#E1E4E8;">    onPressed</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> () {</span></span>
<span class="line"><span style="color:#E1E4E8;">      </span><span style="color:#79B8FF;">ChangeNotifierProvider</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">of</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">CartModel</span><span style="color:#E1E4E8;">&gt;(context).</span><span style="color:#B392F0;">add</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">Item</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">20.0</span><span style="color:#E1E4E8;">, </span><span style="color:#79B8FF;">1</span><span style="color:#E1E4E8;">));</span></span>
<span class="line"><span style="color:#E1E4E8;">    },</span></span>
<span class="line"><span style="color:#E1E4E8;">  );</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">Builder</span><span style="color:#24292E;">(builder</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> (context) {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;ElevatedButton build&quot;</span><span style="color:#24292E;">); </span><span style="color:#6A737D;">// 构建时输出日志</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">ElevatedButton</span><span style="color:#24292E;">(</span></span>
<span class="line"><span style="color:#24292E;">    child</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Text</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;添加商品&quot;</span><span style="color:#24292E;">),</span></span>
<span class="line"><span style="color:#24292E;">    onPressed</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> () {</span></span>
<span class="line"><span style="color:#24292E;">      </span><span style="color:#005CC5;">ChangeNotifierProvider</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">of</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">CartModel</span><span style="color:#24292E;">&gt;(context).</span><span style="color:#6F42C1;">add</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">Item</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">20.0</span><span style="color:#24292E;">, </span><span style="color:#005CC5;">1</span><span style="color:#24292E;">));</span></span>
<span class="line"><span style="color:#24292E;">    },</span></span>
<span class="line"><span style="color:#24292E;">  );</span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><p>我们点击”添加商品“按钮后，由于购物车商品总价会变化，所以显示总价的Text更新是符合预期的，但是”添加商品“按钮本身没有变化，是不应该被重新build的。但是我们运行示例，每次点击”添加商品“按钮，控制台都会输出&quot;ElevatedButton build&quot;日志，也就是说”添加商品“按钮在每次点击时其自身都会重新build！这是为什么呢？如果你已经理解了<code>InheritedWidget</code>的更新机制，那么答案一眼就能看出：这是因为构建<code>ElevatedButton</code>的<code>Builder</code>中调用了<code>ChangeNotifierProvider.of</code>，也就是说依赖了Widget树上面的<code>InheritedWidget</code>（即<code>InheritedProvider</code> ）Widget，所以当添加完商品后，<code>CartModel</code>发生变化，会通知<code>ChangeNotifierProvider</code>, 而<code>ChangeNotifierProvider</code>则会重新构建子树，所以<code>InheritedProvider</code>将会更新，此时依赖它的子孙Widget就会被重新构建。</p><p>问题的原因搞清楚了，那么我们如何避免这不必要重构呢？既然按钮重新被build是因为按钮和<code>InheritedWidget</code>建立了依赖关系，那么我们只要打破或解除这种依赖关系就可以了。那么如何解除按钮和<code>InheritedWidget</code>的依赖关系呢？我们上一节介绍<code>InheritedWidget</code>时已经讲过了：调用<code>dependOnInheritedWidgetOfExactType()</code> 和 <code>getElementForInheritedWidgetOfExactType()</code>的区别就是前者会注册依赖关系，而后者不会。所以我们只需要将<code>ChangeNotifierProvider.of</code>的实现改为下面这样即可：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">//添加一个listen参数，表示是否建立依赖关系</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">static</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">of</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt;(</span><span style="color:#79B8FF;">BuildContext</span><span style="color:#E1E4E8;"> context, {</span><span style="color:#79B8FF;">bool</span><span style="color:#E1E4E8;"> listen </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">true</span><span style="color:#E1E4E8;">}) {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">final</span><span style="color:#E1E4E8;"> type </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">_typeOf</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">InheritedProvider</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt;&gt;();</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">final</span><span style="color:#E1E4E8;"> provider </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> listen</span></span>
<span class="line"><span style="color:#E1E4E8;">        </span><span style="color:#F97583;">?</span><span style="color:#E1E4E8;"> context.</span><span style="color:#B392F0;">dependOnInheritedWidgetOfExactType</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">InheritedProvider</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt;&gt;()</span></span>
<span class="line"><span style="color:#E1E4E8;">        </span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> context.</span><span style="color:#B392F0;">getElementForInheritedWidgetOfExactType</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">InheritedProvider</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt;&gt;()</span><span style="color:#F97583;">?</span><span style="color:#E1E4E8;">.widget</span></span>
<span class="line"><span style="color:#E1E4E8;">            </span><span style="color:#F97583;">as</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">InheritedProvider</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">T</span><span style="color:#E1E4E8;">&gt;;</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> provider.data;</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">//添加一个listen参数，表示是否建立依赖关系</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">static</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">T</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">of</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt;(</span><span style="color:#005CC5;">BuildContext</span><span style="color:#24292E;"> context, {</span><span style="color:#005CC5;">bool</span><span style="color:#24292E;"> listen </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">true</span><span style="color:#24292E;">}) {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">final</span><span style="color:#24292E;"> type </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">_typeOf</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">InheritedProvider</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt;&gt;();</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">final</span><span style="color:#24292E;"> provider </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> listen</span></span>
<span class="line"><span style="color:#24292E;">        </span><span style="color:#D73A49;">?</span><span style="color:#24292E;"> context.</span><span style="color:#6F42C1;">dependOnInheritedWidgetOfExactType</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">InheritedProvider</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt;&gt;()</span></span>
<span class="line"><span style="color:#24292E;">        </span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> context.</span><span style="color:#6F42C1;">getElementForInheritedWidgetOfExactType</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">InheritedProvider</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt;&gt;()</span><span style="color:#D73A49;">?</span><span style="color:#24292E;">.widget</span></span>
<span class="line"><span style="color:#24292E;">            </span><span style="color:#D73A49;">as</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">InheritedProvider</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">T</span><span style="color:#24292E;">&gt;;</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> provider.data;</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span></code></pre></div><p>然后我们将调用部分代码改为：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#79B8FF;">Column</span><span style="color:#E1E4E8;">(</span></span>
<span class="line"><span style="color:#E1E4E8;">    children</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">&lt;</span><span style="color:#79B8FF;">Widget</span><span style="color:#F97583;">&gt;</span><span style="color:#E1E4E8;">[</span></span>
<span class="line"><span style="color:#E1E4E8;">      </span><span style="color:#79B8FF;">Consumer</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">CartModel</span><span style="color:#E1E4E8;">&gt;(</span></span>
<span class="line"><span style="color:#E1E4E8;">        builder</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> (</span><span style="color:#79B8FF;">BuildContext</span><span style="color:#E1E4E8;"> context, cart) </span><span style="color:#F97583;">=&gt;</span><span style="color:#79B8FF;">Text</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;总价: ${</span><span style="color:#79B8FF;">cart</span><span style="color:#9ECBFF;">.</span><span style="color:#79B8FF;">totalPrice</span><span style="color:#9ECBFF;">}&quot;</span><span style="color:#E1E4E8;">),</span></span>
<span class="line"><span style="color:#E1E4E8;">      ),</span></span>
<span class="line"><span style="color:#E1E4E8;">      </span><span style="color:#79B8FF;">Builder</span><span style="color:#E1E4E8;">(builder</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> (context) {</span></span>
<span class="line"><span style="color:#E1E4E8;">        </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;ElevatedButton build&quot;</span><span style="color:#E1E4E8;">);</span></span>
<span class="line"><span style="color:#E1E4E8;">        </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">ElevatedButton</span><span style="color:#E1E4E8;">(</span></span>
<span class="line"><span style="color:#E1E4E8;">          child</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Text</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;添加商品&quot;</span><span style="color:#E1E4E8;">),</span></span>
<span class="line"><span style="color:#E1E4E8;">          onPressed</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> () {</span></span>
<span class="line"><span style="color:#E1E4E8;">            </span><span style="color:#6A737D;">// listen 设为false，不建立依赖关系</span></span>
<span class="line"><span style="color:#E1E4E8;">            </span><span style="color:#79B8FF;">ChangeNotifierProvider</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">of</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">CartModel</span><span style="color:#E1E4E8;">&gt;(context, listen</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">false</span><span style="color:#E1E4E8;">)</span></span>
<span class="line"><span style="color:#E1E4E8;">                .</span><span style="color:#B392F0;">add</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">Item</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">20.0</span><span style="color:#E1E4E8;">, </span><span style="color:#79B8FF;">1</span><span style="color:#E1E4E8;">));</span></span>
<span class="line"><span style="color:#E1E4E8;">          },</span></span>
<span class="line"><span style="color:#E1E4E8;">        );</span></span>
<span class="line"><span style="color:#E1E4E8;">      })</span></span>
<span class="line"><span style="color:#E1E4E8;">    ],</span></span>
<span class="line"><span style="color:#E1E4E8;">  )</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">Column</span><span style="color:#24292E;">(</span></span>
<span class="line"><span style="color:#24292E;">    children</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">&lt;</span><span style="color:#005CC5;">Widget</span><span style="color:#D73A49;">&gt;</span><span style="color:#24292E;">[</span></span>
<span class="line"><span style="color:#24292E;">      </span><span style="color:#005CC5;">Consumer</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">CartModel</span><span style="color:#24292E;">&gt;(</span></span>
<span class="line"><span style="color:#24292E;">        builder</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> (</span><span style="color:#005CC5;">BuildContext</span><span style="color:#24292E;"> context, cart) </span><span style="color:#D73A49;">=&gt;</span><span style="color:#005CC5;">Text</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;总价: ${</span><span style="color:#005CC5;">cart</span><span style="color:#032F62;">.</span><span style="color:#005CC5;">totalPrice</span><span style="color:#032F62;">}&quot;</span><span style="color:#24292E;">),</span></span>
<span class="line"><span style="color:#24292E;">      ),</span></span>
<span class="line"><span style="color:#24292E;">      </span><span style="color:#005CC5;">Builder</span><span style="color:#24292E;">(builder</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> (context) {</span></span>
<span class="line"><span style="color:#24292E;">        </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;ElevatedButton build&quot;</span><span style="color:#24292E;">);</span></span>
<span class="line"><span style="color:#24292E;">        </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">ElevatedButton</span><span style="color:#24292E;">(</span></span>
<span class="line"><span style="color:#24292E;">          child</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Text</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;添加商品&quot;</span><span style="color:#24292E;">),</span></span>
<span class="line"><span style="color:#24292E;">          onPressed</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> () {</span></span>
<span class="line"><span style="color:#24292E;">            </span><span style="color:#6A737D;">// listen 设为false，不建立依赖关系</span></span>
<span class="line"><span style="color:#24292E;">            </span><span style="color:#005CC5;">ChangeNotifierProvider</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">of</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">CartModel</span><span style="color:#24292E;">&gt;(context, listen</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">false</span><span style="color:#24292E;">)</span></span>
<span class="line"><span style="color:#24292E;">                .</span><span style="color:#6F42C1;">add</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">Item</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">20.0</span><span style="color:#24292E;">, </span><span style="color:#005CC5;">1</span><span style="color:#24292E;">));</span></span>
<span class="line"><span style="color:#24292E;">          },</span></span>
<span class="line"><span style="color:#24292E;">        );</span></span>
<span class="line"><span style="color:#24292E;">      })</span></span>
<span class="line"><span style="color:#24292E;">    ],</span></span>
<span class="line"><span style="color:#24292E;">  )</span></span></code></pre></div><p>修改后再次运行上面的示例，我们会发现点击”添加商品“按钮后，控制台不会再输出&quot;ElevatedButton build&quot;了，即按钮不会被重新构建了。而总价仍然会更新，这是因为<code>Consumer</code>中调用<code>ChangeNotifierProvider.of</code>时<code>listen</code>值为默认值true，所以还是会建立依赖关系。</p><p>至此我们便实现了一个迷你的Provider，它具备Pub上Provider Package中的核心功能；但是我们的迷你版功能并不全面，如只实现了一个可监听的ChangeNotifierProvider，并没有实现只用于数据共享的Provider；另外，我们的实现有些边界也没有考虑的到，比如如何保证在Widget树重新build时Model始终是单例等。所以建议读者在实战中还是使用Provider Package，而本节实现这个迷你Provider的主要目的主要是为了帮助读者了解Provider Package底层的原理。</p><h2 id="_7-3-4-其他状态管理包" tabindex="-1">7.3.4 其他状态管理包 <a class="header-anchor" href="#_7-3-4-其他状态管理包" aria-label="Permalink to &quot;7.3.4 其他状态管理包&quot;">​</a></h2><p>现在Flutter社区已经有很多专门用于状态管理的包了，在此我们列出几个相对评分比较高的：</p><table><thead><tr><th>包名</th><th>介绍</th></tr></thead><tbody><tr><td><a href="https://pub.flutter-io.cn/packages/provider" target="_blank" rel="noreferrer">Provider</a> &amp; <a href="https://pub.flutter-io.cn/packages/scoped_model" target="_blank" rel="noreferrer">Scoped Model</a></td><td>这两个包都是基于<code>InheritedWidget</code>的，原理相似</td></tr><tr><td><a href="https://pub.flutter-io.cn/packages/flutter_redux" target="_blank" rel="noreferrer">Redux</a></td><td>是Web开发中React生态链中Redux包的Flutter实现</td></tr><tr><td><a href="https://pub.dev/packages/flutter_mobx" target="_blank" rel="noreferrer">MobX</a></td><td>是Web开发中React生态链中MobX包的Flutter实现</td></tr><tr><td><a href="https://pub.dev/packages/flutter_bloc" target="_blank" rel="noreferrer">BLoC</a></td><td>是BLoC模式的Flutter实现</td></tr></tbody></table><p>在此笔者不对这些包做推荐，读者有兴趣都可以研究一下，了解它们各自的思想。</p><h2 id="_7-3-5-总结" tabindex="-1">7.3.5 总结 <a class="header-anchor" href="#_7-3-5-总结" aria-label="Permalink to &quot;7.3.5 总结&quot;">​</a></h2><p>本节通过介绍事件总线在跨组件共享中的一些缺点引出了通过<code>InheritedWidget</code>来实现状态的共享的思想，然后基于该思想实现了一个简单的 Provider，在实现的过程中也更深入的探索了<code>InheritedWidget</code>与其依赖项的注册机制和更新机制。通过本节的学习，读者应该达到两个目标，首先是对<code>InheritedWidget</code>彻底吃透，其次是 Provider 的设计思想。</p><p><code>InheritedWidget</code>是Flutter中非常重要的一个Widget，像国际化、主题等都是通过它来实现，所以我们也不惜篇幅，通过好几节来介绍它的，在下一节中，我们将介绍另一个基于<code>InheritedWidget</code>的组件Theme(主题)。</p></div></div></main><footer class="VPDocFooter" data-v-6b87e69f data-v-ef5dee53><!--[--><!--]--><div class="edit-info" data-v-ef5dee53><div class="edit-link" data-v-ef5dee53><a class="VPLink link vp-external-link-icon no-icon edit-link-button" href="https://gitee.com/luoguangguang/note/tree/master/docs/largeFrontEnd/flutter/chapter7/provider.md" target="_blank" rel="noreferrer" data-v-ef5dee53><!--[--><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="edit-link-icon" aria-label="edit icon" data-v-ef5dee53><path d="M18,23H4c-1.7,0-3-1.3-3-3V6c0-1.7,1.3-3,3-3h7c0.6,0,1,0.4,1,1s-0.4,1-1,1H4C3.4,5,3,5.4,3,6v14c0,0.6,0.4,1,1,1h14c0.6,0,1-0.4,1-1v-7c0-0.6,0.4-1,1-1s1,0.4,1,1v7C21,21.7,19.7,23,18,23z"></path><path d="M8,17c-0.3,0-0.5-0.1-0.7-0.3C7,16.5,6.9,16.1,7,15.8l1-4c0-0.2,0.1-0.3,0.3-0.5l9.5-9.5c1.2-1.2,3.2-1.2,4.4,0c1.2,1.2,1.2,3.2,0,4.4l-9.5,9.5c-0.1,0.1-0.3,0.2-0.5,0.3l-4,1C8.2,17,8.1,17,8,17zM9.9,12.5l-0.5,2.1l2.1-0.5l9.3-9.3c0.4-0.4,0.4-1.1,0-1.6c-0.4-0.4-1.2-0.4-1.6,0l0,0L9.9,12.5z M18.5,2.5L18.5,2.5L18.5,2.5z"></path></svg> 在Gitee上参与编辑此页<!--]--></a></div><!----></div><nav class="prev-next" data-v-ef5dee53><div class="pager" data-v-ef5dee53><!----></div><div class="pager" data-v-ef5dee53><a class="pager-link next" href="./largeFrontEnd/flutter/chapter1/index.html" data-v-ef5dee53><span class="desc" data-v-ef5dee53>Next page</span><span class="title" data-v-ef5dee53>第一章 初识Flutter</span></a></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><footer class="VPFooter has-sidebar" data-v-1919c326 data-v-e03eb2e1><div class="container" data-v-e03eb2e1><p class="message" data-v-e03eb2e1>Released under the MIT License.</p><p class="copyright" data-v-e03eb2e1>Copyright © 2023-present LG of GZU</p></div></footer><!--[--><!--]--></div></div>
    <script>window.__VP_HASH_MAP__=JSON.parse("{\"backend_index.md\":\"0cb07c7c\",\"largefrontend_electron_index.md\":\"adab8e13\",\"largefrontend_flutter_chapter1_index.md\":\"5106cc23\",\"index.md\":\"20a66851\",\"largefrontend_flutter_chapter10_intro.md\":\"5756d1e8\",\"largefrontend_flutter_chapter10_index.md\":\"87e47f16\",\"largefrontend_flutter_chapter1_flutter_intro.md\":\"9ad5fc78\",\"largefrontend_flutter_chapter12_package_and_plugin.md\":\"c2f14cd7\",\"largefrontend_flutter_chapter12_flutter_web.md\":\"f4b6b743\",\"largefrontend_flutter_chapter10_combine.md\":\"333319d8\",\"largefrontend_flutter_chapter14_flutter_ui_system.md\":\"a1011f7b\",\"largefrontend_flutter_chapter11_index.md\":\"35dcdd7c\",\"largefrontend_flutter_chapter12_index.md\":\"890b799c\",\"largefrontend_flutter_chapter13_index.md\":\"6db9b579\",\"largefrontend_flutter_chapter14_index.md\":\"87f7da6b\",\"largefrontend_flutter_chapter1_mobile_development_intro.md\":\"40c15ac2\",\"largefrontend_flutter_chapter10_turn_box.md\":\"6a792fe1\",\"largefrontend_flutter_chapter3_index.md\":\"bc1d0de5\",\"largefrontend_flutter_chapter4_stack.md\":\"3f5c3186\",\"largefrontend_flutter_chapter1_install_flutter.md\":\"4543c368\",\"largefrontend_flutter_chapter14_paint.md\":\"8f7289b0\",\"largefrontend_flutter_chapter5_padding.md\":\"9fadce05\",\"largefrontend_flutter_chapter4_index.md\":\"f9b298f7\",\"largefrontend_flutter_chapter2_flutter_package_mgr.md\":\"4a3b7161\",\"largefrontend_flutter_chapter11_socket.md\":\"e8264e44\",\"largefrontend_flutter_chapter4_intro.md\":\"1341b5fd\",\"largefrontend_flutter_chapter14_update.md\":\"e4d2c2f0\",\"largefrontend_flutter_chapter5_index.md\":\"455baa0a\",\"largefrontend_flutter_chapter4_alignment.md\":\"a6596610\",\"largefrontend_flutter_chapter13_multi_languages_support.md\":\"c113238d\",\"largefrontend_flutter_chapter11_dio.md\":\"64f4e813\",\"largefrontend_flutter_chapter2_first_flutter_app.md\":\"b650181d\",\"largefrontend_flutter_chapter2_flutter_app_debug.md\":\"67a72433\",\"largefrontend_flutter_chapter2_state_manage.md\":\"9bb80d37\",\"largefrontend_flutter_chapter6_index.md\":\"5a321b81\",\"largefrontend_flutter_chapter5_material_scaffold.md\":\"8e6b896a\",\"largefrontend_flutter_chapter3_buttons.md\":\"ef950360\",\"largefrontend_flutter_chapter10_done_widget.md\":\"c3b44318\",\"largefrontend_flutter_chapter6_single_child_scrollview.md\":\"e3f75f3b\",\"largefrontend_flutter_chapter14_paint_flow.md\":\"d2f8102a\",\"largefrontend_flutter_chapter6_intro.md\":\"125a064e\",\"largefrontend_flutter_chapter5_transform.md\":\"22708e1e\",\"largefrontend_flutter_chapter14_layer.md\":\"4ed449fc\",\"largefrontend_flutter_chapter11_websocket.md\":\"0a022e47\",\"largefrontend_flutter_chapter5_fittedbox.md\":\"db915726\",\"largefrontend_flutter_chapter2_index.md\":\"d8e937b7\",\"largefrontend_flutter_chapter3_radio_and_checkbox.md\":\"025aba21\",\"largefrontend_flutter_chapter13_locallization_implement.md\":\"dc4b83fe\",\"largefrontend_flutter_chapter2_thread_model_and_error_report.md\":\"a29199d6\",\"largefrontend_flutter_chapter5_decoratedbox.md\":\"20f093ba\",\"largefrontend_flutter_chapter14_render_object.md\":\"55a1b551\",\"largefrontend_flutter_chapter14_element_buildcontext.md\":\"4272eae4\",\"largefrontend_flutter_chapter4_wrap_and_flow.md\":\"ac41b5bd\",\"largefrontend_flutter_chapter11_file_operation.md\":\"996a3a5d\",\"largefrontend_flutter_chapter13_faq.md\":\"ba7b9c70\",\"largefrontend_webfrontend_md_10.md\":\"51e0a312\",\"largefrontend_webfrontend_md_24.md\":\"0a4abd08\",\"largefrontend_flutter_chapter14_flutter_app_startup.md\":\"9b5942a1\",\"largefrontend_flutter_chapter10_custom_paint.md\":\"8b2a0a46\",\"largefrontend_flutter_chapter2_flutter_assets_mgr.md\":\"0e38b701\",\"largefrontend_interview_01.md\":\"2ac4b56d\",\"largefrontend_flutter_chapter8_index.md\":\"e83d3d80\",\"largefrontend_webfrontend_md_16.md\":\"a5610416\",\"largefrontend_flutter_chapter9_index.md\":\"3fb342a7\",\"largefrontend_flutter_chapter8_listener.md\":\"1b9b0316\",\"largefrontend_webfrontend_md_37.md\":\"3cacf3a2\",\"largefrontend_flutter_chapter4_layoutbuilder.md\":\"3d4bf94b\",\"largefrontend_webfrontend_md_17.md\":\"ee74edfb\",\"largefrontend_webfrontend_md_13.md\":\"b180bb5b\",\"largefrontend_flutter_chapter7_index.md\":\"0eb456b2\",\"largefrontend_webfrontend_md_31.md\":\"309453c7\",\"largefrontend_webfrontend_md_25.md\":\"95fdb4fe\",\"largefrontend_webfrontend_md_12.md\":\"3b14e491\",\"largefrontend_webfrontend_md_23.md\":\"18f08d72\",\"largefrontend_flutter_chapter11_json_model.md\":\"c84d2ccf\",\"largefrontend_webfrontend_md_01.md\":\"fbb7a35f\",\"largefrontend_flutter_chapter3_progress.md\":\"9bc148d3\",\"largefrontend_webfrontend_md_18.md\":\"ee651cc6\",\"largefrontend_flutter_sponsor.md\":\"e71431a9\",\"largefrontend_webfrontend_md_36.md\":\"f22f6d0d\",\"largefrontend_webfrontend_md_07.md\":\"71c2ad1d\",\"largefrontend_webfrontend_md_19.md\":\"e7907728\",\"largefrontend_webfrontend_md_20.md\":\"5a68bb4f\",\"largefrontend_webfrontend_md_32.md\":\"91d2f39f\",\"largefrontend_flutter_chapter7_futurebuilder_and_streambuilder.md\":\"af3535c0\",\"largefrontend_flutter_chapter9_hero.md\":\"25b46cf2\",\"largefrontend_flutter_chapter8_notification.md\":\"909f6756\",\"largefrontend_webfrontend_md_08.md\":\"0d59dce4\",\"largefrontend_flutter_chapter3_img_and_icon.md\":\"8b409b55\",\"largefrontend_webfrontend_md_04.md\":\"d6c15d55\",\"largefrontend_flutter_chapter9_animated_switcher.md\":\"9c0b3119\",\"largefrontend_webfrontend_md_22.md\":\"7d6fea68\",\"largefrontend_flutter_chapter2_flutter_widget_intro.md\":\"13414fea\",\"largefrontend_flutter_chapter13_intl.md\":\"d4776610\",\"largefrontend_overview_index.md\":\"3c87f69c\",\"largefrontend_flutter_chapter5_container.md\":\"373cc694\",\"largefrontend_wechatminiprogram_index.md\":\"7f40708d\",\"largefrontend_webfrontend_md_38.md\":\"3b6bb332\",\"linux_index.md\":\"624ecc66\",\"largefrontend_webfrontend_md_35.md\":\"f0538423\",\"myteam_index.md\":\"91a2c11f\",\"largefrontend_flutter_chapter6_pageview.md\":\"36fcbc65\",\"largefrontend_webfrontend_md_03.md\":\"2e5087f0\",\"largefrontend_webfrontend_md_21.md\":\"c181316e\",\"largefrontend_flutter_chapter3_input_and_form.md\":\"e4fba9dd\",\"largefrontend_flutter_chapter14_compositing.md\":\"6d96f932\",\"largefrontend_webfrontend_md_29.md\":\"c6fada7d\",\"largefrontend_flutter_chapter4_constraints.md\":\"9e4baace\",\"largefrontend_webfrontend_md_11.md\":\"63cd9c49\",\"largefrontend_webfrontend_md_14.md\":\"1423aeb1\",\"largefrontend_flutter_chapter6_tabview.md\":\"56048fb1\",\"largefrontend_webfrontend_md_33.md\":\"fdbe86fa\",\"largefrontend_flutter_chapter6_nestedscrollview.md\":\"2a66b86a\",\"largefrontend_webfrontend_md_34.md\":\"ad8ea220\",\"largefrontend_flutter_chapter2_flutter_router.md\":\"bb6e776c\",\"largefrontend_webfrontend_md_30.md\":\"cd2cb5aa\",\"largefrontend_flutter_chapter4_flex.md\":\"ebd43d6a\",\"largefrontend_webfrontend_md_09.md\":\"eedafcb1\",\"largefrontend_webfrontend_md_40.md\":\"4d4fefa1\",\"largefrontend_flutter_join_us.md\":\"44c81d86\",\"largefrontend_flutter_chapter9_route_transition.md\":\"f56cf837\",\"largefrontend_uniapp_index.md\":\"fa387c39\",\"largefrontend_flutter_chapter4_row_and_column.md\":\"964229f5\",\"largefrontend_flutter_chapter9_stagger_animation.md\":\"315538f5\",\"largefrontend_flutter_chapter3_text.md\":\"6720230c\",\"largefrontend_flutter_chapter10_watermark.md\":\"2e4ddf03\",\"largefrontend_flutter_chapter11_http.md\":\"efd2ee64\",\"largefrontend_webfrontend_md_06.md\":\"e20b049a\",\"largefrontend_flutter_summary.md\":\"2e31b0a8\",\"largefrontend_flutter_chapter6_animatedlist.md\":\"20d9436f\",\"largefrontend_flutter_chapter5_clip.md\":\"91f4174c\",\"largefrontend_webfrontend_md_02.md\":\"40cd2099\",\"largefrontend_flutter_chapter6_gridview.md\":\"b3be7e60\",\"largefrontend_flutter_chapter6_custom_scrollview.md\":\"01be950c\",\"largefrontend_flutter_chapter11_download_with_chunks.md\":\"9379cc89\",\"largefrontend_flutter_chapter6_scroll_controller.md\":\"ffa2d5fd\",\"largefrontend_flutter_chapter9_intro.md\":\"3fc29b5f\",\"largefrontend_flutter_chapter1_dart.md\":\"6bba4e7c\",\"largefrontend_flutter_chapter7_inherited_widget.md\":\"5a21d704\",\"largefrontend_flutter_index.md\":\"cd81fbbe\",\"largefrontend_flutter_reference.md\":\"36336375\",\"largefrontend_flutter_chapter6_keepalive.md\":\"535137be\",\"largefrontend_flutter_chapter14_layout.md\":\"0d7a8df3\",\"largefrontend_flutter_chapter6_sliver.md\":\"0c8b7553\",\"largefrontend_webfrontend_md_39.md\":\"aef49a57\",\"largefrontend_webfrontend_md_15.md\":\"bf9ff1a1\",\"largefrontend_flutter_chapter14_image_and_cache.md\":\"9622c56b\",\"largefrontend_webfrontend_md_28.md\":\"83169d10\",\"largefrontend_flutter_chapter8_eventbus.md\":\"fc0db86d\",\"largefrontend_flutter_chapter7_value_listenable_builder.md\":\"a0c76121\",\"largefrontend_flutter_preface.md\":\"604b9934\",\"largefrontend_flutter_chapter7_theme.md\":\"c21036bc\",\"largefrontend_webfrontend_md_05.md\":\"f7607009\",\"largefrontend_flutter_chapter6_listview.md\":\"472910bd\",\"largefrontend_flutter_chapter7_provider.md\":\"ab590744\",\"largefrontend_flutter_chapter8_gesture.md\":\"859bbb38\",\"largefrontend_flutter_chapter9_animated_widgets.md\":\"e8cd3c4d\",\"largefrontend_webfrontend_md_26.md\":\"4928006b\",\"largefrontend_flutter_chapter10_gradient_circular_progress_demo.md\":\"b3d48a2c\",\"largefrontend_flutter_chapter8_hittest.md\":\"e963812b\",\"largefrontend_flutter_chapter7_willpopscope.md\":\"d224ecce\",\"largefrontend_flutter_chapter9_animation_structure.md\":\"672eb3c0\",\"largefrontend_flutter_chapter8_gesture_conflict.md\":\"15bbadba\",\"largefrontend_webfrontend_md_27.md\":\"0b5b5e39\",\"largefrontend_flutter_chapter7_dailog.md\":\"5f91e51a\",\"largefrontend_flutter_chapter10_custom_checkbox.md\":\"0db7d50f\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"zh-CN\",\"dir\":\"ltr\",\"title\":\"落光的Pro博客\",\"description\":\"Vite & Vue powered static site generator.\",\"base\":\"./\",\"head\":[],\"appearance\":true,\"themeConfig\":{\"search\":{\"provider\":\"local\",\"options\":{\"locales\":{\"zh\":{\"translations\":{\"button\":{\"buttonText\":\"搜索文档\",\"buttonAriaLabel\":\"搜索文档\"},\"modal\":{\"noResultsText\":\"无法找到相关结果\",\"resetButtonTitle\":\"清除查询条件\",\"footer\":{\"selectText\":\"选择\",\"navigateText\":\"切换\"}}}}}}},\"logo\":\"/icon-radius.png\",\"nav\":[{\"text\":\"大前端\",\"items\":[{\"text\":\"Web前端\",\"link\":\"/largeFrontEnd/webFrontEnd/md/01.md\"},{\"text\":\"Uni-app\",\"link\":\"/largeFrontEnd/uniapp/\"},{\"text\":\"微信小程序\",\"link\":\"/largeFrontEnd/weChatMiniProgram/\"},{\"text\":\"Electron\",\"link\":\"/largeFrontEnd/electron/\"},{\"text\":\"Flutter\",\"link\":\"/largeFrontEnd/flutter/\"},{\"text\":\"前端面试题\",\"link\":\"/largeFrontEnd/interview/01.md\"}]},{\"text\":\"后端\",\"link\":\"/backEnd/\"},{\"text\":\"Linux\",\"link\":\"/linux/\"},{\"text\":\"我的团队\",\"link\":\"/myTeam/\"}],\"sidebar\":{\"/largeFrontEnd/webFrontEnd/\":[{\"text\":\"第一阶段  基础入门\",\"collapsed\":true,\"items\":[{\"text\":\"一、基础认知\",\"link\":\"/largeFrontEnd/webFrontEnd/md/01.md\"},{\"text\":\"二、HTML标签学习\",\"link\":\"/largeFrontEnd/webFrontEnd/md/02.md\"},{\"text\":\"三、HTML基础\",\"link\":\"/largeFrontEnd/webFrontEnd/md/03.md\"},{\"text\":\"四、CSS基础\",\"link\":\"/largeFrontEnd/webFrontEnd/md/04.md\"},{\"text\":\"五、CSS进阶\",\"link\":\"/largeFrontEnd/webFrontEnd/md/05.md\"},{\"text\":\"六、盒子模型\",\"link\":\"/largeFrontEnd/webFrontEnd/md/06.md\"},{\"text\":\"七、CSS浮动\",\"link\":\"/largeFrontEnd/webFrontEnd/md/07.md\"},{\"text\":\"八、CSS定位装饰\",\"link\":\"/largeFrontEnd/webFrontEnd/md/08.md\"},{\"text\":\"九、CSS精灵图\",\"link\":\"/largeFrontEnd/webFrontEnd/md/09.md\"},{\"text\":\"项目前置认知\",\"link\":\"/largeFrontEnd/webFrontEnd/md/10.md\"},{\"text\":\"项目结构搭建\",\"link\":\"/largeFrontEnd/webFrontEnd/md/11.md\"},{\"text\":\"字体图标、动画\",\"link\":\"/largeFrontEnd/webFrontEnd/md/12.md\"},{\"text\":\"移动web开发\",\"link\":\"/largeFrontEnd/webFrontEnd/md/13.md\"}]},{\"text\":\"第二阶段 技术进阶\",\"collapsed\":true,\"items\":[{\"text\":\"JavaScript深入浅出\",\"link\":\"/largeFrontEnd/webFrontEnd/md/14.md\"},{\"text\":\"JavaScript核心之web APIs\",\"link\":\"/largeFrontEnd/webFrontEnd/md/15.md\"},{\"text\":\"一、Web APIS导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/16.md\"},{\"text\":\"二、DOM导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/17.md\"},{\"text\":\"三、事件高级导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/18.md\"},{\"text\":\"四、BOM导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/19.md\"},{\"text\":\"五、PC网页特效导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/20.md\"},{\"text\":\"六、移动端特效导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/21.md\"},{\"text\":\"七、本地存储导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/22.md\"},{\"text\":\"jQuery入门导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/23.md\"},{\"text\":\"数据可视化项目导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/24.md\"}]},{\"text\":\"Node.js\",\"collapsed\":true,\"items\":[{\"text\":\"buffer(缓冲器)\",\"link\":\"/largeFrontEnd/webFrontEnd/md/25.md\"},{\"text\":\"计算机基础\",\"link\":\"/largeFrontEnd/webFrontEnd/md/26.md\"},{\"text\":\"fs模块\",\"link\":\"/largeFrontEnd/webFrontEnd/md/27.md\"},{\"text\":\"path模块\",\"link\":\"/largeFrontEnd/webFrontEnd/md/28.md\"},{\"text\":\"HTTP模块\",\"link\":\"/largeFrontEnd/webFrontEnd/md/29.md\"},{\"text\":\"Express框架\",\"link\":\"/largeFrontEnd/webFrontEnd/md/30.md\"},{\"text\":\"Mongodb\",\"link\":\"/largeFrontEnd/webFrontEnd/md/31.md\"}]},{\"text\":\"Ajax\",\"link\":\"/largeFrontEnd/webFrontEnd/md/32.md\"},{\"text\":\"前端面试题\",\"collapsed\":true,\"items\":[{\"text\":\"一、CSS\",\"link\":\"/largeFrontEnd/webFrontEnd/md/33.md\"},{\"text\":\"二、JavaScript\",\"link\":\"/largeFrontEnd/webFrontEnd/md/34.md\"},{\"text\":\"三、HTML5CSS3\",\"link\":\"/largeFrontEnd/webFrontEnd/md/35.md\"},{\"text\":\"四、Vue\",\"link\":\"/largeFrontEnd/webFrontEnd/md/36.md\"},{\"text\":\"五、Echarts\",\"link\":\"/largeFrontEnd/webFrontEnd/md/37.md\"},{\"text\":\"六.Uni-APP\",\"link\":\"/largeFrontEnd/webFrontEnd/md/38.md\"},{\"text\":\"七、webpack\",\"link\":\"/largeFrontEnd/webFrontEnd/md/39.md\"},{\"text\":\"八、Git\",\"link\":\"/largeFrontEnd/webFrontEnd/md/40.md\"}]}],\"/largeFrontEnd/flutter/\":[{\"text\":\"Flutter入门到实战\",\"collapsed\":false,\"items\":[{\"text\":\"第一章 初识Flutter\",\"link\":\"/largeFrontEnd/flutter/chapter1/index.md\"},{\"text\":\"第二章 简介\",\"link\":\"/largeFrontEnd/flutter/chapter2/index.md\"},{\"text\":\"第三章 基础组件\",\"link\":\"/largeFrontEnd/flutter/chapter3/index.md\"},{\"text\":\"第四章 布局类组件\",\"link\":\"/largeFrontEnd/flutter/chapter4/index.md\"},{\"text\":\"第五章 容器类Widget\",\"link\":\"/largeFrontEnd/flutter/chapter5/index.md\"},{\"text\":\"第六章 可滚动组件\",\"link\":\"/largeFrontEnd/flutter/chapter6/index.md\"},{\"text\":\"第七章 功能型Widget简介\",\"link\":\"/largeFrontEnd/flutter/chapter7/index.md\"},{\"text\":\"第八章 事件处理与通知\",\"link\":\"/largeFrontEnd/flutter/chapter8/index.md\"},{\"text\":\"第九章 动画\",\"link\":\"/largeFrontEnd/flutter/chapter9/index.md\"},{\"text\":\"第十章 自定义组件\",\"link\":\"/largeFrontEnd/flutter/chapter10/index.md\"},{\"text\":\"第十一章 文件操作\",\"link\":\"/largeFrontEnd/flutter/chapter11/index.md\"},{\"text\":\"第十二章 Flutter 扩展\",\"link\":\"/largeFrontEnd/flutter/chapter12/index.md\"},{\"text\":\"第十三章 多语言\",\"link\":\"/largeFrontEnd/flutter/chapter13/index.md\"},{\"text\":\"第十四章 高级进阶\",\"link\":\"/largeFrontEnd/flutter/chapter14/index.md\"}]}]},\"socialLinks\":[{\"icon\":\"github\",\"link\":\"https://gitee.com/luoguangguang\"},{\"icon\":{\"svg\":\"<svg role=\\\"img\\\" viewBox=\\\"0 0 24 24\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><title>Dribbble</title><path d=\\\"M12...6.38z\\\"/></svg>\"},\"link\":\"...\",\"ariaLabel\":\"cool link\"}],\"footer\":{\"message\":\"Released under the MIT License.\",\"copyright\":\"Copyright © 2023-present LG of GZU\"},\"editLink\":{\"pattern\":\"https://gitee.com/luoguangguang/note/tree/master/docs/:path\",\"text\":\"在Gitee上参与编辑此页\"},\"carbonAds\":{\"code\":\"your-carbon-code\",\"placement\":\"your-carbon-placement\"}},\"locales\":{},\"scrollOffset\":90,\"cleanUrls\":false}");</script>
    
  </body>
</html>